/*******************************************************************************
 * Copyright (c) 2000, 2006 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/

package com.xored.searchwt.highlight;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.ITextEditor;

/**
 * @author Yuri Strot
 *
 */
public class EditorAnnotationManager {
	
	private Highlighter highlighter;
	private IDocument document;
	private Display display;
	
	private IMatchesListener listener;
	
	public static final int HIGHLLIGHTER_ANY= 0;
	public static final int HIGHLIGHTER_MARKER= 1;
	public static final int HIGHLIGHTER_ANNOTATION= 2;
	
	public EditorAnnotationManager(IEditorPart editorPart, IMatchesListener listener) {
		Assert.isNotNull(editorPart);
		document = getDocument(editorPart);
		if (document != null)
			highlighter = createHighlighter(editorPart);
		display = editorPart.getSite().getShell().getDisplay();
		this.listener = listener;
	}
	
	public IDocument getDocument() {
		return document;
	}
	
	public boolean isEnabled() {
		return highlighter != null;
	}
	
	public void highlight(final Match[] matches) {
		if (display != null && !display.isDisposed()) {
			display.asyncExec(new Runnable() {
			
				public void run() {
					removeAllAnnotations();
					addAnnotations(matches);
				}
			
			});
		}
	}
	
	public void highlight(final String text) {
		if (display != null && !display.isDisposed()) {
			display.asyncExec(new Runnable() {
			
				public void run() {
					removeAllAnnotations();
					if (text == null || text.length() == 0 || highlighter == null)
						return;
					String source = document.get();
					int index = 0;
					List matches = new ArrayList();
					while(true) {
						index = source.indexOf(text, index);
						if (index >= 0) {
							matches.add(new Match(index, text.length()));
							index++;
						}
						else
							break;
					}
					addAnnotations((Match[])matches.toArray(new Match[matches.size()]));
				}
			
			});
		}
	}

	public void dispose() {
		removeAllAnnotations();
		if (highlighter != null) {
			highlighter.dispose();
			highlighter = null;
		}
	}

	private void removeAllAnnotations() {
		if (highlighter != null) {
			highlighter.removeAll();
			listener.matched(IMatchesListener.EMPTY);
		}
	}

	private Highlighter createHighlighter(IEditorPart editor) {
		IAnnotationModel model= getAnnotationModel(editor);
		if (model != null)
			return new AnnotationHighlighter(model, document);
		IEditorInput input= editor.getEditorInput();
		if (input instanceof IFileEditorInput) {
			IFile file= ((IFileEditorInput)input).getFile();
			if (file != null)
				return new MarkerHighlighter(file);
		}
		return new Highlighter(); // does nothing
	}

	public void addAnnotations(Match[] matches) {
		if (highlighter != null) {
			highlighter.addHighlights(matches);
			listener.matched(matches);
		}
	}

	public void removeAnnotations(Match[] matches) {
		if (highlighter != null) {
			highlighter.removeHighlights(matches);
			listener.matched(IMatchesListener.EMPTY);
		}
	}

	private static IAnnotationModel getAnnotationModel(IWorkbenchPart part) {
		IAnnotationModel model= null;
		model= (IAnnotationModel) part.getAdapter(IAnnotationModel.class); 
		if (model == null) {
			ITextEditor textEditor= null;
			if (part instanceof ITextEditor) {
				textEditor= (ITextEditor) part; 
			}
			if (textEditor != null) {
				IDocumentProvider dp= textEditor.getDocumentProvider();
				if (dp != null)
					model= dp.getAnnotationModel(textEditor.getEditorInput());
			}
		}
		return model;
	}

	private static IDocument getDocument(IWorkbenchPart part) {
		IDocument doc= null;
		doc= (IDocument) part.getAdapter(IDocument.class); 
		if (doc == null) {
			ITextEditor textEditor= null;
			if (part instanceof ITextEditor) {
				textEditor= (ITextEditor) part; 
			}
			if (textEditor != null) {
				IDocumentProvider dp= textEditor.getDocumentProvider();
				if (dp != null)
					doc= dp.getDocument(textEditor.getEditorInput());
			}
		}
		return doc;
	}
}
